package com.atzly.community.service.impl;

import com.atzly.community.entity.DiscussPost;
import com.atzly.community.mapper.DiscussPostMapper;
import com.atzly.community.mapper.elastaticsearch.DiscussPostRepository;
import com.atzly.community.service.ElastaticSearchService;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author zlysimida
 * @date 2021/9/2 - 8:07
 */
@Service
@Slf4j
public class ElastaticSearchServiceImpl implements ElastaticSearchService {

    @Autowired
    private DiscussPostRepository repository;

    @Autowired
    private DiscussPostMapper discussPostMapper;

    @Autowired
    private ElasticsearchTemplate elasticTemplate;

    @Override
    public void addEntityToEs(DiscussPost post) {
        repository.save(post);
    }

    @Override
    public void removeEntityFromEs(int id) {
        repository.deleteById(id);
    }

    // restHighClient
//    @Override
//    public Map<String,Object> searchFromEs(String keyword, int offset, int limit) {
//        // 构造查询
//        SearchRequest searchRequest = new SearchRequest("discusspost");
//        SearchSourceBuilder builder = new SearchSourceBuilder();
//        builder.query(QueryBuilders.multiMatchQuery(keyword,  "title", "content"));
//        builder.sort(SortBuilders.fieldSort("type").order(SortOrder.DESC))
//                .sort(SortBuilders.fieldSort("score").order(SortOrder.DESC))
//                .sort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC));
//
//        // 分页
//        builder.from(offset);
//        builder.size(limit);
//
//        // 高亮显示
//        builder.highlighter(new HighlightBuilder().field("title").preTags("<em>").postTags("</em>"))
//                .highlighter(new HighlightBuilder().field("content").preTags("<em>").postTags("</em>"));
//
//        // 设置超时时间
//        // builder.timeout(new TimeValue(60, TimeUnit.SECONDS));
//        searchRequest.source(builder);
//        try {
//            SearchResponse response = elasticsearchTemplate.search(searchRequest, RequestOptions.DEFAULT);
//            // 回传数据
//            Map<String,Object> res =new HashMap<>();
//            long hitCounts = response.getHits().getTotalHits().value;
//            if(hitCounts != 0){
//                res.put("hitCounts",hitCounts);
//            }
//            // 进行分页处理
//            List<DiscussPost> page = new ArrayList<>();
//            if(response.getHits() != null){
//                for (SearchHit hit : response.getHits().getHits()) {
//                    DiscussPost post = new DiscussPost();
//                    String id = hit.getSourceAsMap().get("id").toString();
//                    post.setId(Integer.parseInt(id));
//                    String userId = hit.getSourceAsMap().get("userId").toString();
//                    post.setUserId(Integer.parseInt(userId));
//                    String title = hit.getSourceAsMap().get("title").toString();
//                    post.setTitle(title);
//                    String content = hit.getSourceAsMap().get("content").toString();
//                    post.setContent(content);
//                    String type = hit.getSourceAsMap().get("type").toString();
//                    post.setType(Integer.parseInt(type));
//                    String status = hit.getSourceAsMap().get("status").toString();
//                    post.setStatus(Integer.parseInt(status));
//                    String createTime = hit.getSourceAsMap().get("createTime").toString();
//                    post.setCreateTime(new Date(Long.parseLong(createTime)));
//                    String commentCount = hit.getSourceAsMap().get("commentCount").toString();
//                    post.setCommentCount(Integer.parseInt(commentCount));
//                    // 空指针异常
//                    // String scorer = hit.getSourceAsMap().get("scorer").toString();
//                    // post.setScore(Double.parseDouble(scorer));
//
//                    // 处理高亮字段
//                    HighlightField titleField = hit.getHighlightFields().get("title");
//                    if(titleField != null){
//                        // 只显示第一处高亮标题
//                        post.setTitle(titleField.getFragments()[0].toString());
//                    }
//                    HighlightField contentField = hit.getHighlightFields().get("content");
//                    if(contentField != null){
//                        // 只显示第一处高亮标题
//                        post.setContent(contentField.getFragments()[0].toString());
//                    }
//                    page.add(post);
//                }
//            }
//            res.put("page",page);
//            return res;
//        } catch (IOException e) {
//           log.error("构造查询条件失败! err{}",e.getMessage());
//           throw new RuntimeException("构造查询条件失败!"+e.getMessage());
//        }
//    }

    @Override
    public Page<DiscussPost> searchDiscussPost(String keyword, int current, int limit) {
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.multiMatchQuery(keyword, "title", "content"))
                .withSort(SortBuilders.fieldSort("type").order(SortOrder.DESC))
                .withSort(SortBuilders.fieldSort("score").order(SortOrder.DESC))
                .withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
                .withPageable(PageRequest.of(current, limit))
                .withHighlightFields(
                        new HighlightBuilder.Field("title").preTags("<em>").postTags("</em>"),
                        new HighlightBuilder.Field("content").preTags("<em>").postTags("</em>")
                ).build();

        return elasticTemplate.queryForPage(searchQuery, DiscussPost.class, new SearchResultMapper() {
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> aClass, Pageable pageable) {
                SearchHits hits = response.getHits();
                if (hits.getTotalHits() <= 0) {
                    return null;
                }

                List<DiscussPost> list = new ArrayList<>();
                for (SearchHit hit : hits) {
                    DiscussPost post = new DiscussPost();

                    String id = hit.getSourceAsMap().get("id").toString();
                    post.setId(Integer.valueOf(id));

                    String userId = hit.getSourceAsMap().get("userId").toString();
                    post.setUserId(Integer.valueOf(userId));

                    String title = hit.getSourceAsMap().get("title").toString();
                    post.setTitle(title);

                    String content = hit.getSourceAsMap().get("content").toString();
                    post.setContent(content);

                    String status = hit.getSourceAsMap().get("status").toString();
                    post.setStatus(Integer.valueOf(status));

                    String createTime = hit.getSourceAsMap().get("createTime").toString();
                    post.setCreateTime(new Date(Long.valueOf(createTime)));

                    String commentCount = hit.getSourceAsMap().get("commentCount").toString();
                    post.setCommentCount(Integer.valueOf(commentCount));

                    // 处理高亮显示的结果
                    HighlightField titleField = hit.getHighlightFields().get("title");
                    if (titleField != null) {
                        post.setTitle(titleField.getFragments()[0].toString());
                    }

                    HighlightField contentField = hit.getHighlightFields().get("content");
                    if (contentField != null) {
                        post.setContent(contentField.getFragments()[0].toString());
                    }

                    list.add(post);
                }

                return new AggregatedPageImpl(list, pageable,
                        hits.getTotalHits(), response.getAggregations(), response.getScrollId(), hits.getMaxScore());
            }
        });
    }

}
